home *** CD-ROM | disk | FTP | other *** search
- #!/bin/sh -- need to mention perl here to avoid recursion
- 'true' || eval 'exec perl -S $0 $argv:q';
- eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec /usr/local/bin/perl -S $0 $argv:q'
- if 0;
-
- #
- # Pass.chk -- a password guesser. Functionally equivalent to the original
- # cops password guesser. The -P option doesn't work right now (alpha release,
- # don't you know :-), since we're doing funky things with password caching,
- # but this will change soon.
- #
- # Usage: $0 [options] dictionary
- #
- # -P pfile password file (not working)
- # -p print found passwords (incompatible with -M)
- # -d check prefix/suffix of digits [0-9]
- # -g check all words in gcos, plan, project, signature files
- # -r reverse the word tests
- # -s check all single chars as passwords
- # -u output the current user being checked
- # -U try uppercase word tests
- # -v verbose, print advisory information
- # -x check guess+prefix/suffix with strange chars added on
- # -0 (zero) change all o's ("oh"'s) to 0 (zeros)
- # -1 (one) change all i's to 1 (ones)
- # -m misspell words -- chop off first and last chars,
- # if > 3 chars. E.g. "dinner" ==> "inner" and "dinne"
- #
- # Originally written by Tim Tessin with lots more features, etc., etc., etc.
- # I ripped out all of his extra functionality that duplicated some of the
- # other cops stuff, and some things that just didn't fit, and added some
- # code to finish the simulation of the old checker. -- dan
- #
-
- require "getopts.pl";
- # can probably just do "|| &usage;" since &usage is only used once. ;-)
- &Getopts("p0dgrsuUv1P:mx") || print STDERR "Usage: $0 -p0xdgrsuUPvm\n";
-
- # diff password file?
- if (defined($opt_P)) { $'GET_PASSWD = "/bin/cat $opt_P"; }
- require "pass.cache.pl";
-
- $Passwd = "/etc/passwd";
- @strange_things = (" ", ";", ",", ".", "!", "@", "#", "$",
- "%", "^", "&", "*", "(", ")", "-", "_",
- "=", "+", "[", "]", "{", "}", "'", "\"",
- "|", "`", "~", ">", "<");
-
- # unbuffer output
- select (STDOUT); $| = 1;
-
- $dups = 0; # duplicate name entries
- $new = 0; # new entries
- $changed = 0; # password (and other data) changed
- $deleted = 0; # deleted entries
- $updated = 0; # data other than password changed
- $nlog = 0; # number of log entries, used for print decisions
- $ntest = 0;
- $ndone = 0;
-
- for $uid (keys %uname2passwd) {
- next if length($pass = $uname2passwd{$uid}) != 13;
- next unless $pass; # shall we report null passwd's, too? ;-)
- if ($try = &dopwd()) {
- $pwd = ($opt_p) ? $try : "";
- # printf "Username: %-8s <password guessed> $pwd\n",$P[0];
- printf "Warning! $uid password Problem: Guessed: %s\t\t$pwd\n",$P[0];
- }
- $ndone++;
- }
-
- 1;
- # end of program
-
-
- ######################## Support Subroutines ###########################
- # dopwd tests each password entry against several simple checks and all
- # the words in the dictionaries specified. The simple checks consists
- # of trying the username as the password ('joe' accounts), words derived
- # from the gecos fields (usually first and last names).
-
- sub dopwd {
- $tries = 0;
-
- print "$uid\n" if ($opt_u);
-
- # try user name
- ($try = &testpwd($uid,$pass)) && return $try;
- # try uiduid
- if (length($uid) < 8) {
- ($try = &testpwd($uid . $uid,$pass)) && return $try;
- }
-
- # do gcos field?
- if ($opt_g) {
- @gcos = split(/[.,& -]/,$uname2gcos{$uid});
- foreach $i (@gcos) {
- next unless $i; # skip null split values
- ($try = &testpwd($i,$pass)) && return $try;
- }
-
- # Try names from misc files
- #
- undef %words;
- # files to check
- @files2chk = ("/.project", "/.plan", "/.signature");
- $home = $uname2dir{$uid};
- for $i (@files2chk) {
- open (FOOFILE, $home . $i);
- while (<FOOFILE>) {
- chop;
- @line = split(/([.,;\s])/);
- for $j (@line) {
- $words{$j}=$j unless $j=~/[\s]/;
- }
- }
- close FOOFILE;
- }
- for $k (values %words) {
- # print "word $k\n";
- ($try = &testpwd($k,$pass)) && return $try;
- }
- }
-
- # do dictionaries
- # save state of upper/reverse so individual dicts can temporarily
- # override.
- foreach $i (@ARGV) {
- if (open (DICT,$i)) {
- while (<DICT>) {
- chop;
- if ($try = &testpwd($_,$pass)) {
- close DICT;
- return $try;
- }
- }
- close DICT;
- }
- }
- return 0;
- }
-
-
- # small subroutines to help the main password cracker. All are labeled
- # p_xxx, where xxx is the identifying name.
- #
-
- # if leading character is upper-case, also try lower case version
- sub p_lc {
- local($try) = @_;
- local($ntry);
- if ( $try =~ /^[A-Z]/ ) {
- ($ntry = $try) =~ y/A-Z/a-z/;
- push(@total_guesses, $ntry);
- }
- }
-
- # reverse check
- sub p_rev {
- local($try) = @_;
- local($ntry);
- $ntry = reverse $try;
- if ($ntry ne $try) {
- push(@total_guesses, $ntry);
- }
- }
-
- # uppercase check
- sub p_up {
- local($try) = @_;
- local($ntry);
- ($ntry = $try) =~ y/a-z/A-Z/;
- if ($ntry ne $try) { push(@total_guesses, $ntry); }
- }
-
- # testpwd checks a word to see if it matches the encrpted password
- # if the word is capitalized, the lowercase version is tried as well
-
- sub testpwd {
- local ($try,$pass) = @_;
- local (@total_guesses);
-
- push(@total_guesses, $try);
-
- # free (lower case) check if first letter is uppercase
- &p_lc($try);
- # reverse?
- if ($opt_r) { &p_rev($try); }
- # uppercase?
- if ($opt_U) { &p_up($try); }
-
- # single digit tacked on to beginning and end
- if ($opt_d) {
- if (length ($try) < 8) {
- foreach $i ('0'..'9') {
- $ntry = $i.$try;
- push(@total_guesses, $ntry);
- if ($opt_r) { &p_rev($ntry); }
- if ($opt_U) { &p_up($ntry); }
- }
- foreach $i ('0'..'9') {
- $ntry = $try.$i;
- push(@total_guesses, $ntry);
- if ($opt_r) { &p_rev($ntry); }
- if ($opt_U) { &p_up($ntry); }
- }
- }
- }
-
- # change o's to 0's ("oh"'s to zeros)
- if ($opt_0) {
- if (($ntry = $try) =~ s/o/0/g) { push(@total_guesses, $ntry); }
- }
- if ($opt_1) {
- if (($ntry = $try) =~ s/i/1/g) { push(@total_guesses, $ntry); }
- }
-
- # misspell words -- truncate first and last letter, if > 3 chars
- # thanks to William Vajk, learn@ddsw1.MCS.COM, who posted this idea.
- if ($opt_m) {
- $len = length($try);
- if ($len > 3) {
- ($ntry = $try) =~ s/^.//; push(@total_guesses, $ntry);
- if ($len < 9) {
- ($ntry = $try) =~ s/.$//; push(@total_guesses, $ntry);
- }
- }
- }
-
- # weird things! Tacked on to beginning and end
- if ($opt_x) {
- if (length ($try) < 8) {
- foreach $i (@strange_things) {
- $ntry = $i.$try;
- push(@total_guesses, $ntry);
- if ($opt_r) { &p_rev($ntry); }
- if ($opt_U) { &p_up($ntry); }
- }
- foreach $i (@strange_things) {
- $ntry = $try.$i;
- push(@total_guesses, $ntry);
- if ($opt_r) { &p_rev($ntry); }
- if ($opt_U) { &p_up($ntry); }
- }
- }
- }
-
- # do single letters, #'s, if needed
- if ($opt_s && $uid ne $last_user) {
- $last_user = $uid;
- foreach $i (@strange_things) { push(@total_guesses,$i); }
- foreach $i (0..9) { push(@total_guesses, $i); }
- foreach $i (A..Z) { push(@total_guesses, $i); }
- foreach $i (a..z) { push(@total_guesses, $i); }
- }
-
- if ($opt_v) {
- foreach $i (@total_guesses) {
- print "Trying \"$i\" on $uid\n";
- $epw = crypt($i,$pass);
- ($epw eq $pass) && return $i;
- }
- }
- else {
- foreach $i (@total_guesses) {
- $epw = crypt($i,$pass);
- ($epw eq $pass) && return $i;
- }
- }
- undef @total_guesses;
-
- return 0;
- }
-